{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "233c84f6",
   "metadata": {},
   "source": [
    "## Adding Pip Dependencies to an Electron\n",
    "\n",
    "There are three ways to declare Pip package dependencies to an electron:\n",
    "\n",
    "1. Assign the dependencies directly in the Covalent `DepsPip` class.\n",
    "2. Specify a requirements file containing the dependencies.\n",
    "3. Use the electron's `call_before()` and `call_after()` hooks.\n",
    "\n",
    "All three methods are illustrated below.\n",
    "\n",
    "### Prerequisites\n",
    "\n",
    "Import `covalent` and the packages required by the electron."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "5b50cb81",
   "metadata": {},
   "outputs": [],
   "source": [
    "import covalent as ct\n",
    "import numpy"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "fcb4306c",
   "metadata": {},
   "source": [
    "Optionally, if you're going to assign dependencies from a requirements file, create the file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "4f4b3677",
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('requirements_example.txt', 'w') as f:\n",
    "    f.write('numpy==1.22.4')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb5ead5c",
   "metadata": {},
   "source": [
    "### Procedure\n",
    "\n",
    "#### Using the DepsPip Class\n",
    "\n",
    "1. Create a Covalent `DepsPip` object, passing a list of package assignments as the `packages` keyword argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "3c7f8d9c",
   "metadata": {},
   "outputs": [],
   "source": [
    "deps_numpy = ct.DepsPip(packages=[\"numpy==1.22.4\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8baba2c",
   "metadata": {},
   "source": [
    "#### Specifying a Requirements File\n",
    "\n",
    "1. To use a requirements file instead, pass the file path to the `DepsPip` class as the `reqs_path` keyword rather than passing the `packages` list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "6b821dfb",
   "metadata": {},
   "outputs": [],
   "source": [
    "deps_numpy = ct.DepsPip(reqs_path=\"./requirements_example.txt\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0a6b5516",
   "metadata": {},
   "source": [
    "2. In either case, once the `DepsPip` object is created, pass it to the electron decorator as the `deps_pip` keyword argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "84dc23dc",
   "metadata": {},
   "outputs": [],
   "source": [
    "@ct.electron(\n",
    "    deps_pip=deps_numpy\n",
    ")\n",
    "def get_result():\n",
    "    matrix = numpy.identity(3)\n",
    "    return numpy.sum(matrix)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ceb586e7",
   "metadata": {},
   "source": [
    "#### Using call_before() and call_after()\n",
    "\n",
    "1. Rather than assign a `DepsPip` object in the `deps_pip` argument, you can assign a `DepsPip` object to either the `call_before()` or `call_after()` hook on an electron, or assign a different `DepsPip` object to both."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "884ecd28",
   "metadata": {},
   "outputs": [],
   "source": [
    "@ct.electron(\n",
    "    call_before = [ct.DepsPip(packages=[\"numpy==1.22.4\"])],\n",
    "    call_after = [ct.DepsPip(packages=[\"networkx==2.8.6\"])]\n",
    ")\n",
    "def get_result():\n",
    "    matrix = numpy.identity(3)\n",
    "    return numpy.sum(matrix)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8b4260cf",
   "metadata": {},
   "source": [
    "### Complete the Workflow\n",
    "\n",
    "Regardless of how you've assigned the dependencies, assign the electron to a workflow and dispatch the workflow as you normally would."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "858feca3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.0\n"
     ]
    }
   ],
   "source": [
    "@ct.lattice\n",
    "def workflow():\n",
    "    return get_result()\n",
    "\n",
    "dispatch_id = ct.dispatch(workflow)()\n",
    "res = ct.get_result(dispatch_id, wait=True)\n",
    "print(res.result)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  },
  "vscode": {
   "interpreter": {
    "hash": ""
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
